#pragma once
#include "compiler.hpp"
#include "runner.hpp"
#include "../common/util.hpp"
#include <signal.h>
#include <unistd.h>
#include <jsoncpp/json/json.h>
using namespace std;

class CompileAndRun
{
public:
    static void RemoveTempFile(const string &file_name)
    {
        // 清理文件的个数是不确定的，但是有哪些我们是知道的
        string _src = PathUtil::Src(file_name);
        if(FileUtil::IsFileExists(_src)) 
            unlink(_src.c_str());

        string _compiler_error = PathUtil::CompilerError(file_name);
        if(FileUtil::IsFileExists(_compiler_error)) 
            unlink(_compiler_error.c_str());

        string _execute = PathUtil::Exe(file_name);
        if(FileUtil::IsFileExists(_execute)) 
            unlink(_execute.c_str());

        string _stdin = PathUtil::Stdin(file_name);
        if(FileUtil::IsFileExists(_stdin)) 
            unlink(_stdin.c_str());

        string _stdout = PathUtil::Stdout(file_name);
        if(FileUtil::IsFileExists(_stdout)) 
            unlink(_stdout.c_str());

        string _stderr = PathUtil::Stderr(file_name);
        if(FileUtil::IsFileExists(_stderr)) 
            unlink(_stderr.c_str());
    }
    // code > 0 : 进程收到了信号导致异常奔溃
    // code < 0 : 整个过程非运行报错(代码为空，编译报错等)
    // code = 0 : 整个过程全部完成
    static string CodeToDesc(int code, const string &file_name)
    {
        string desc;
        switch (code)
        {
        case 0:
            desc = "编译运行成功";
            break;
        case -1:
            desc = "提交的代码是空";
            break;
        case -2:
            desc = "未知错误";
            break;
        case -3:
            // desc = "代码编译的时候发生了错误";
            FileUtil::ReadFile(PathUtil::CompilerError(file_name), &desc, true);
            break;
        case SIGABRT: // 6
            desc = "内存超过范围";
            break;
        case SIGXCPU: // 24
            desc = "CPU使用超时";
            break;
        case SIGFPE: // 8
            desc = "浮点数溢出";
            break;
        default:
            desc = "未知: " + to_string(code);
            break;
        }
        return desc;
    }

    static void Start(const string &in_json, string *out_json)
    {
        Json::Value in_value;
        Json::Reader reader;
        reader.parse(in_json, in_value);

        string code = in_value["code"].asString();
        string input = in_value["input"].asString();
        int cpu_limit = in_value["cpu_limit"].asInt();
        int mem_limit = in_value["mem_limit"].asInt();

        int status_code = 0;
        Json::Value out_value;
        int run_result = 0;
        string file_name;

        if (code.size() == 0)
        {
            status_code = -1;
            goto END;
        }
        file_name = FileUtil::UniqFileName();
        // 形成临时src文件
        if (!FileUtil::WriteFile(PathUtil::Src(file_name), code))
        {
            status_code = -2; //未知错误
            goto END;
        }

        if (!Compiler::Compile(file_name))
        {
            //编译失败
            status_code = -3; //代码编译的时候发生了错误
            goto END;
        }

        run_result = Runner::Run(file_name, cpu_limit, mem_limit);
        if (run_result < 0)
        {
            status_code = -2; //未知错误
        }
        else if (run_result > 0)
        {
            //程序运行崩溃了
            status_code = run_result;
        }
        else
        {
            //运行成功
            status_code = 0;
        }
    END:
        out_value["status"] = status_code;
        out_value["reason"] = CodeToDesc(status_code, file_name);
        if (status_code == 0)
        {
            // 整个过程全部成功
            string _stdout;
            FileUtil::ReadFile(PathUtil::Stdout(file_name), &_stdout, true);
            out_value["stdout"] = _stdout;

            string _stderr;
            FileUtil::ReadFile(PathUtil::Stderr(file_name), &_stderr, true);
            out_value["stderr"] = _stderr;
        }
        Json::StyledWriter writer;
        *out_json = writer.write(out_value);
        RemoveTempFile(file_name);
    }
};
